遠端資料請求的方式有幾種,早期通常是透過原生 AJAX 或是 jQuery 包裝後的 AJAX 來請求資料,現在大多是使用 fetch
或 axios
,兩者差別在於 fetch
是原生的 API,axios
是一個基於 AJAX 打包過後的套件,下面列出兩者的特性:
fetch
使用 ES6 的 Promise
作回應。then
作為下一步的執行。catch
當作錯誤回應。ReadableStream
物件,需要使用不同資料類型的對應方法取得資料物件。fetch
只對網絡請求報錯,對400,500都當做成功的請求。fetch
默認不會帶cookie,需要添加配置項。fetch
沒有辦法原生監聽請求的進度,而XHR可以。fetch
跨域處理的性能比 XHR 要好。瀏覽器發送的請求是不能隨便跨域的,一定要藉助其他方式協助跨域,而 fetch
可以直接設置 mode
為「no-cors」來實現跨域訪問。如前一篇所提,在 class component 請求數據,通常是在 componentDidMount
中執行,要注意的是,fetch
因為是原生 API,所以能直接使用,axios
則需要先安裝後,再 import
使用。function component 中請求數據的方式也可以參考前一篇使用 react hook 的方式。
import axios from 'axios'
class TestComponent extends React.Component {
state = {
data: []
}
async componentDidMount () {
// fetch
const data = await fetch('https://randomuser.me/api/', {}).then(res => res.json())
if (data) {
this.setState({data: data})
}
// axios
const res = await axios('https://randomuser.me/api/')
if ( result && result.data) {
this.setState({data: result.data})
}
}
render() {
const { data } = this.state
return (
<div>
{ userData }
</div>
);
}
}
通常一個比較完善的產品,都會將 API 進行統一的管理,方便工程師進行開發和維護,不管是 fetch
或是 axios
,在開發中通常都會先打包起來,讓其他工程師可以直接調用,不需要去寫許多重複的程式碼。
fetch
封裝範例我們先建立一支 JS 檔,api.js 當作管理 API 的檔案,接著將 fetch
封裝為一個函式,裡面有兩個參數,第一個參數是使用 fetch
本身常用的一些參數配置,第二個參數是比較不常用或不會經常改動的參數配置。這個函式最後會返回 fetch
請求的結果
// api.js
export default ({ url, method, headers, data }, option = {}) => {
return fetch(url, { // url 請求位置
method: method || 'GET', //請求方法
// 發送給伺服器的資料
body: data ? JSON.stringfy(data) : null,
headers: headers || {
'content-type': 'application/json'
},
mode: 'cors', // 跨域處理
...option // 其他配置
}).then(res => res.json())
}
使用的時候,我們可以在元件中引入 api.js 來調用,如下
import api from './utils/api.js'
const getData = api({ url: '/api/userData', data: { id: 'userId' } })
axios
也是先建立一支 JS 檔做管理,一樣封裝成一個函式,最後會返回請求結果,函式的參數同樣分為常用配置和不常用配置,封裝完畢後,一樣可以在元件中進行調用。
export default ({ url, method, headers, data }, option = {}) => {
return fetch(url, { // url 請求位置
method: method || 'GET', //請求方法
// 發送給伺服器的資料
data,
headers: headers || {
'content-type': 'application/json'
},
...options
})
}
上面雖然有將 API 請求的基本方式做封裝了,但如果直接就在各個元件中進行請求,在管理上仍然非常麻煩,因此通常會按照不同類型的功能,區分為不同的檔案進行資料請求。
下面的案例我們建立一個 user.js,所有和 user 資料相關的請求都會在這個檔案內執行,像是 getAllUser()
、getUser(id)
都是單純的取得資料,就繼續使用 GET
方法,如果是像 addUser
這種新增或更新資料的情況,就使用 POST
。這邊使用 static
,是因為靜態屬性不需要實例化也可以調用,可以減少內存的配置。
import api from './utils/api.js'
export default class user {
// 取得所有用戶
static getAllUser() {
return api({
url: '/api/allUser'
})
}
// 取得當前用戶
static getUser(id) {
return api({
url: '/api/user/${id}'
})
}
// 新增用戶
static addUser(data) {
return api({
url: '/api/addUser',
methid: 'POST',
data
})
}
}
之後我們只要在元件中進行調用即可。
import userApi from '../service/user'
class UserProfile extends React.Component {
state = {
user: []
}
async componentDidMount () {
const user = await userApi.getUser('userId')
if (user) {
this.setState({user: user})
}
}
render() {
const { user } = this.state
return (
<div>
{ user }
</div>
);
}
}
由於課程對 fetch
和 axios
的介紹比較少,這篇文章中使用了一些自己之前做的筆記,因為當時有參考網路上的文章,所以在下面附上參考資料。